package xjf_etcd

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/go-kratos/kratos/v2/log"
	"github.com/go-kratos/kratos/v2/transport/http"
	clientv3 "go.etcd.io/etcd/client/v3"
	"google.golang.org/grpc"
	"math/rand"
	"time"
)

// @Author Chenlin
// @Description key value的value对象，注册到etcd中的参数
// @time 2023/7/31

type EtcdValue struct {
	Ip   string `json:"ip" bson:"ip"`
	Http string `json:"http" bson:"http"`
	Grpc string `json:"grpc" bson:"grpc"`
}

// @Author Chenlin
// @Description EtcdCase etcd interface
// @time 2023/7/31

type etcdCase interface {
	HttpCall(ctx context.Context, key string) (*http.Client, error)
	GrpcCall(ctx context.Context, key string) (*grpc.ClientConn, error)
	RegisterServer(ctx context.Context, key string, value *EtcdValue) error
	DiscoverServer(ctx context.Context, key string) error
}

type XjfEtcd struct {
	client    *clientv3.Client
	serverMap map[string][]*EtcdValue
}

// @Author Chenlin
// @Description New xjf etcd struct
// @time 2023/7/31

func NewXjfEtcd(endPoints []string) *XjfEtcd {
	xjf_Etcd := &XjfEtcd{}
	client, err := clientv3.New(clientv3.Config{
		Endpoints:   endPoints,
		DialTimeout: time.Second * 2,
	})
	if err != nil {
		log.Fatal(err)
	}
	xjf_Etcd.client = client
	serverMap := make(map[string][]*EtcdValue, 0)
	xjf_Etcd.serverMap = serverMap
	return xjf_Etcd
}

// @Author Chenlin
// @Description 注册服务到etcd
// @time 2023/7/31

func (c *XjfEtcd) RegisterServer(ctx context.Context, key string, value *EtcdValue) error {
	grant, err2 := c.client.Grant(ctx, 10)
	if err2 != nil {
		return err2
	}
	leaseId := grant.ID
	marshal, err := json.Marshal(value)
	if err != nil {
		return err
	}
	if _, err2 := c.client.Put(ctx, key, string(marshal), clientv3.WithLease(leaseId)); err2 != nil {
		return err2
	}
	fmt.Printf("注册%s成功\n", key)
	if err2 := c.RegisterKeepAlive(ctx, key, string(marshal), leaseId); err2 != nil {
		return err2
	}
	return nil
}

// @Author Chenlin
// @Description 服务发现
// @time 2023/7/31

func (c *XjfEtcd) DiscoverServer(ctx context.Context, key string) error {
	serverList := make([]*EtcdValue, 0)
	get, err := c.client.Get(ctx, key, clientv3.WithPrefix())
	if err != nil {
		return err
	}
	for _, v := range get.Kvs {
		etcdValue := &EtcdValue{}
		json.Unmarshal(v.Value, etcdValue)
		serverList = append(serverList, etcdValue)
		fmt.Printf("discover key:%s ,value:%v\n", key, etcdValue)
	}
	c.serverMap[key] = serverList
	c.WatchServer(ctx, key)
	return nil
}

// @Author Chenlin
// @Description 监听服务的数量变化
// @time 2023/7/31

func (c *XjfEtcd) WatchServer(ctx context.Context, key string) {
	watchChan := c.client.Watch(ctx, key, clientv3.WithPrefix())
	go func() {
		for watchResp := range watchChan {
			for _, event := range watchResp.Events {
				if event.Type == clientv3.EventTypePut {
					etcdValue := &EtcdValue{}
					json.Unmarshal(event.Kv.Value, etcdValue)
					c.serverMap[key] = append(c.serverMap[key], etcdValue)
					fmt.Printf("key:%s,add new addr\n", key)
				} else if event.Type == clientv3.EventTypeDelete {
					serverList := make([]*EtcdValue, 0)
					fmt.Printf("key:%s,delete addr\n", key)
					get, err := c.client.Get(ctx, key, clientv3.WithPrefix())
					if err != nil {
						return
					}
					for _, v := range get.Kvs {
						etcdValue := &EtcdValue{}
						json.Unmarshal(v.Value, etcdValue)
						serverList = append(serverList, etcdValue)
						fmt.Printf("discover key:%s ,value:%v\n", key, etcdValue)
					}
					c.serverMap[key] = serverList
				}
			}
		}
	}()
}

// @Author Chenlin
// @Description 服务探活续租
// @time 2023/7/31

func (c *XjfEtcd) RegisterKeepAlive(ctx context.Context, key string, value string, id clientv3.LeaseID) error {
	alive, err := c.client.KeepAlive(ctx, id)
	if err != nil {
		return err
	}
	go func() {
		for {
			select {
			case leaseKeepResp := <-alive:
				if leaseKeepResp == nil {
					fmt.Printf("已经关闭续租功能\n")
					return
				} else {
					if _, err2 := c.client.Put(ctx, key, value, clientv3.WithLease(id)); err2 != nil {
						panic(err2)
					}
					goto END
				}
			}
		END:
			time.Sleep(time.Second * 3)
		}
	}()
	return nil
}

// @Author Chenlin
// @Description 通过服务的key名称获取Http调用
// @time 2023/7/31

func (c *XjfEtcd) HttpCall(ctx context.Context, key string) (*http.Client, error) {
	//随机获取
	values, exist := c.serverMap[key]
	etcdValue := &EtcdValue{}
	if exist {
		if len(values) > 0 && len(values) > 1 { //随机获取
			etcdValue = values[rand.Intn(len(c.serverMap[key]))]
		} else if len(values) > 0 {
			etcdValue = values[0]
		} else { //没有元素
			return nil, errors.New(fmt.Sprintf("%s服务暂不可用", key))
		}
	} else {
		return nil, errors.New(fmt.Sprintf("%s服务暂不可用", key))
	}
	connHttp, err := http.NewClient(
		ctx, http.WithEndpoint(etcdValue.Http), http.WithTimeout(time.Second*2),
	)
	if err != nil {
		return nil, err
	}
	return connHttp, nil
}

// @Author Chenlin
// @Description 通过服务的key名称获取grpc调用
// @time 2023/7/31

func (c *XjfEtcd) GrpcCall(ctx context.Context, key string) (*grpc.ClientConn, error) {
	//随机获取
	values, exist := c.serverMap[key]
	etcdValue := &EtcdValue{}
	if exist {
		if len(values) > 0 && len(values) > 1 { //随机获取
			etcdValue = values[rand.Intn(len(c.serverMap[key]))]
		} else if len(values) > 0 {
			etcdValue = values[0]
		} else { //没有元素
			return nil, errors.New(fmt.Sprintf("%s服务暂不可用", key))
		}
	} else {
		return nil, errors.New(fmt.Sprintf("%s服务暂不可用", key))
	}
	connGRPC, err := grpc.Dial(etcdValue.Grpc, grpc.WithTimeout(2*time.Second))
	if err != nil {
		return nil, err
	}
	return connGRPC, nil
}
